﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using CodeAngel.Domain;
using System.Threading.Tasks;

namespace CodeAngel.Domain.Framework
{
    /// <summary>
    /// Base class for an aggregate that deletes a root entity.
    /// </summary>
    public abstract class DeleteAggregate
    {
        #region DeleteAsync

        /// <summary>
        /// Deletes the identified entity asynchronously.  Uses the credentials from the current logged in user.
        /// </summary>
        /// <param name="id">The ID of the entity to be deleted.</param>
        public Task DeleteAsync(Guid id)
        {
            return this.DeleteAsync(id, User.LoggedInUser);
        }

        /// <summary>
        /// Deletes the identified entity asynchronously, using the identified user to verify permissions to delete.
        /// </summary>
        /// <param name="id">The ID of the entity to be deleted.</param>
        /// <param name="thisUser"></param>
        public Task DeleteAsync(Guid id, User thisUser)
        {
            this.User = thisUser;
            if (!this.UserHasPermissionToDelete())
                throw new Exception("Current user does not have the necessary permissions to delete the data in this aggregate: " + this.GetType().Name);

            return Task.Factory.StartNew(() =>
            {
                var ThisServiceProxy = DomainDataServiceClient.Create();
                ThisServiceProxy.DeleteAsync(this.GetType().FullName, id, thisUser.UserName, thisUser.Password);
            });
        }

        #endregion

        #region User

        /// <summary>
        /// Gets or sets the user.
        /// </summary>
        public User User { get; set; }

        #endregion

        #region UserHasPermissionToDelete

        /// <summary>
        /// Asks the derived aggregate to determine if the current user has permission to Delete the 
        /// updateable entities in the object graph maintained by this aggregate.
        /// </summary>
        public abstract bool UserHasPermissionToDelete();

        #endregion

        #region GetDto

        /// <summary>
        /// Gets an instance of the DTO, whose ID is set with the identified ID.  This is used to 
        /// facilate deleting its corrseponding record from the database.
        /// </summary>
        public abstract IDto GetDto(Guid id);

        #endregion

        #region CreateAggregate

        /// <summary>
        /// Creates and returns a new instance of the identified aggregate type.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public static DeleteAggregate CreateAggregate(string aggregateType)
        {
            // Create the AggregateType
            System.Type AggregateType;
            try
            {
                AggregateType = System.Type.GetType(aggregateType, true);
            }
            catch (Exception ex)
            {
                throw new Exception("Unable to get type of delete aggregate type: " + aggregateType, ex);
            }

            // Instantiate the AggregateType.
            object AggregateTypeInstance;
            try
            {
                AggregateTypeInstance = System.Activator.CreateInstance(AggregateType);
            }
            catch (Exception ex)
            {
                throw new Exception("Unable to create instance of delete aggregate type: " + aggregateType, ex);
            }

            // Verify that the type instantiated is an DeleteAggregate.
            if (AggregateTypeInstance is DeleteAggregate)
                return AggregateTypeInstance as DeleteAggregate;
            else
                throw new Exception("Type does not derive from DeleteAggregate.  Actual Type: " + AggregateTypeInstance.GetType().Name);

        }

        #endregion

    }
}
